package dlt645_2007

import (
	"github.com/sirupsen/logrus"
	"go-iot-gateway/pkg/serial_ext"
	"go.bug.st/serial"
	"sync"
	"time"
)

const (
	serialTimeout     = 5 * time.Second
	serialIdleTimeout = 60 * time.Second
)

// serialPort has configuration and I/O controller.
type serialPort struct {
	//SerialMode  serial.Mode
	SerialParams serial_ext.SerialParams

	Logger       *logrus.Logger
	IdleTimeout  time.Duration
	mu           sync.Mutex
	port         serial.Port
	lastActivity time.Time
	closeTimer   *time.Timer
}

func (dlt *serialPort) Connect() (err error) {
	return dlt._connect()
}

func (dlt *serialPort) _connect() error {
	if dlt.port != nil {
		return nil
	}

	dlt.mu.Lock()
	defer dlt.mu.Unlock()

	if dlt.port == nil {
		dlt.Logger.Debugf("[串口打开]  %+v", dlt.SerialParams)
		port, err := serial.Open(dlt.SerialParams.SerialName, dlt.SerialParams.SerialMode())
		if err != nil {
			return err
		}
		err = port.SetReadTimeout(dlt.SerialParams.ReadTimeout)
		if err != nil {
			return err
		}
		dlt.port = port
		dlt.Logger.Debugf("[串口信息] %+v", dlt.port)
	}
	return nil
}

func (dlt *serialPort) Close() (err error) {
	dlt.mu.Lock()
	defer dlt.mu.Unlock()

	return dlt._close()
}

func (dlt *serialPort) _close() (err error) {
	if dlt.port != nil {
		err = dlt.port.Close()
		dlt.port = nil
	}
	return
}

func (dlt *serialPort) debugf(format string, v ...interface{}) {
	if dlt.Logger != nil {
		dlt.Logger.Debugf(format, v...)
	}
}

func (dlt *serialPort) errorf(format string, v ...interface{}) {
	if dlt.Logger != nil {
		dlt.Logger.Errorf(format, v...)
	}
}

func (dlt *serialPort) startCloseTimer() {
	if dlt.IdleTimeout <= 0 {
		return
	}
	if dlt.closeTimer == nil {
		dlt.closeTimer = time.AfterFunc(dlt.IdleTimeout, dlt.closeIdle)
	} else {
		dlt.closeTimer.Reset(dlt.IdleTimeout)
	}
}

func (dlt *serialPort) closeIdle() {
	dlt.mu.Lock()
	defer dlt.mu.Unlock()

	if dlt.IdleTimeout <= 0 {
		return
	}
	idle := time.Since(dlt.lastActivity) // time.Now().Sub(dlt.lastActivity)
	if idle >= dlt.IdleTimeout {
		dlt.Logger.Warnf(" closing connection due to idle timeout: %v", idle)
		err := dlt._close()
		if err != nil {
			dlt.errorf(" closing error %s", err)
		}
	}
}
